package cn.redis.util.primary;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 不依赖于spring的基于jedis的工具类
 * TIPS: 从其他人的demo中复制了一份稍微修改完善了一下而已，可能并不符合实际的业务需求。由于实际场景不太用不上，所以就不调优了。
 *
 * @author yexi
 */
@Slf4j
public class JedisUtils {
    private final static String HOST;

    private final static Integer PORT;

    private final static String PASSWORD;

    private final static int TIMEOUT;

    private static JedisPool jedisPool;

    static {
        HOST = "localhost";
        PORT = 6379;
        PASSWORD = null;
        TIMEOUT = 0;
        JedisPoolConfig config = new JedisPoolConfig();
        jedisPool = new JedisPool(config, HOST, PORT, TIMEOUT, PASSWORD);
    }

    public static Jedis getClient() {
        try {
            return jedisPool.getResource();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Jedis getClient(int dbIndex) {
        try {
            Jedis jedis = jedisPool.getResource();
            jedis.select(dbIndex);
            return jedis;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static boolean batchSet(Map<String, String> keyValues, int dbIndex) throws Exception {
        Jedis jedis = null;
        Pipeline pipeline = null;
        try {
            jedis = getClient(dbIndex);
            pipeline = jedis.pipelined();
            for (Map.Entry<String, String> entry : keyValues.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                pipeline.set(key, value);
            }
            sync(jedis, pipeline);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public List<String> batchGet(List<String> keys, int dbIndex) throws Exception {
        List<String> retData = new ArrayList<>();
        List<Response<String>> resList = new ArrayList<>();
        Jedis jedis = null;
        Pipeline pipeline = null;
        try {
            jedis = getClient(dbIndex);
            pipeline = jedis.pipelined();
            for (String key : keys) {
                Response<String> ret = pipeline.get(key);
                resList.add(ret);
            }
            sync(jedis, pipeline);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            for (Response<String> response : resList) {
                String retSet = response.get();
                retData.add(retSet);
            }
        }
        return retData;
    }

    public boolean batchZadd(List<String> keys, List<String> values, int dbIndex) throws Exception {
        Jedis jedis = null;
        Pipeline pipeline = null;
        try {
            jedis = getClient(dbIndex);
            pipeline = jedis.pipelined();
            // 这里使用数组索引从设计上不太合理。但是复制过来时就是这样，就不改了。
            for (int i = 0; i < keys.size(); i++) {
                String key = keys.get(i);
                String value = values.get(i);
                // 这里是业务逻辑，请根据实际情况优化score和过期时间
                pipeline.zadd(key, System.currentTimeMillis(), value);
                pipeline.expire(key, 4 * 60 * 60);
            }
            sync(jedis, pipeline);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public List<Set<Tuple>> zrevrangeWithScores(List<String> keys, long start, long end, int dbIndex) throws Exception {
        List<Set<Tuple>> retData = new ArrayList<>();
        List<Response<Set<Tuple>>> resList = new ArrayList<>();
        Jedis jedis = null;
        Pipeline pipeline = null;
        try {
            jedis = getClient(dbIndex);
            pipeline = jedis.pipelined();
            for (String key : keys) {
                Response<Set<Tuple>> response = pipeline.zrevrangeWithScores(key, start, end);
                resList.add(response);
            }
            sync(jedis, pipeline);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            for (int i = 0; i < resList.size(); i++) {
                Set<Tuple> retSet = resList.get(i).get();
                retData.add(retSet);
            }
        }
        return retData;
    }

    public List<Set<Tuple>> zrangeByScoreWithScores(List<String> keys, long start, long end, int dbIndex) throws Exception {
        List<Set<Tuple>> retData = new ArrayList<>();
        List<Response<Set<Tuple>>> resList = new ArrayList<>();
        Jedis jedis = null;
        Pipeline pipeline = null;
        try {
            jedis = getClient(dbIndex);
            pipeline = jedis.pipelined();
            for (String key : keys) {
                Response<Set<Tuple>> response = pipeline.zrangeByScoreWithScores(key, start, end);
                resList.add(response);
            }
            sync(jedis, pipeline);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            for (int i = 0; i < resList.size(); i++) {
                Set<Tuple> retSet = resList.get(i).get();
                retData.add(retSet);
            }
        }
        return retData;
    }


    public static void sync(Jedis jedis, Pipeline pipelined) {
        try {
            if (null != pipelined) {
                pipelined.sync();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(" ============== Redis 批量提交失败 =============== ");
        } finally {
            try {
                if (null != pipelined) {
                    pipelined.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (null != jedis) {
                    jedis.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}
